package com.luhuiguo.sso.entity;

import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.apache.tapestry5.beaneditor.DataType;
import org.apache.tapestry5.beaneditor.NonVisual;
import org.springframework.security.GrantedAuthority;
import org.springframework.security.userdetails.UserDetails;

@Entity
@Table(name = "t_user")
public class User extends AuditableEntity implements UserDetails {

	private static final long serialVersionUID = 3009613749335612507L;

	@NonVisual
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Long id;

	@Column(unique = true, nullable = false)
	private String username;

	@DataType("password")
	private String password;

	private String email;

	@OneToMany(mappedBy = "user", cascade = CascadeType.ALL/*, fetch = FetchType.EAGER*/)
	private Set<Persona> personas = new HashSet<Persona>();

	@NonVisual
	@ManyToOne
	private Persona defaultPersona;

	@NonVisual
	@ManyToMany/*(fetch = FetchType.EAGER)*/
	@JoinTable(name = "t_user_role", joinColumns = { @JoinColumn(name = "user_id") }, inverseJoinColumns = { @JoinColumn(name = "role_id") })
	private Set<Role> roles = new HashSet<Role>();

	@NonVisual
	@Temporal(TemporalType.TIMESTAMP)
	private Date accountExpireDate;

	@NonVisual
	private boolean accountLocked;

	@NonVisual
	@Temporal(TemporalType.TIMESTAMP)
	private Date credentialsExpireDate;

	private boolean enabled = true;

	public User() {
		super();
	}

	public User(String username) {
		super();
		this.username = username;
	}

	public User(String username, String password) {
		super();
		this.username = username;
		this.password = password;
	}

	public User(String username, String password, String email) {
		super();
		this.username = username;
		this.password = password;
		this.email = email;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public Long getId() {
		return id;
	}

	@Override
	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	@Override
	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public void setPersonas(Set<Persona> personas) {
		this.personas = personas;
	}

	public Set<Persona> getPersonas() {
		return personas;
	}

	public Persona getDefaultPersona() {
		return defaultPersona;
	}

	public void setDefaultPersona(Persona defaultPersona) {
		this.defaultPersona = defaultPersona;
	}

	public Date getAccountExpireDate() {
		return accountExpireDate;
	}

	public void setAccountExpireDate(Date accountExpireDate) {
		this.accountExpireDate = accountExpireDate;
	}

	public boolean isAccountLocked() {
		return accountLocked;
	}

	public void setAccountLocked(boolean accountLocked) {
		this.accountLocked = accountLocked;
	}

	public Date getCredentialsExpireDate() {
		return credentialsExpireDate;
	}

	public void setCredentialsExpireDate(Date credentialsExpireDate) {
		this.credentialsExpireDate = credentialsExpireDate;
	}

	public Set<Role> getRoles() {
		return roles;
	}

	public void setRoles(Set<Role> roles) {
		this.roles = roles;
	}

	@NonVisual
	@Transient
	@Override
	public GrantedAuthority[] getAuthorities() {
		return getRoles().toArray(new GrantedAuthority[0]);
	}

	@NonVisual
	@Transient
	@Override
	public boolean isAccountNonExpired() {
		return accountExpireDate == null || accountExpireDate.after(new Date());
	}

	@NonVisual
	@Transient
	@Override
	public boolean isAccountNonLocked() {
		return !accountLocked;
	}

	@NonVisual
	@Transient
	@Override
	public boolean isCredentialsNonExpired() {
		return credentialsExpireDate == null
				|| credentialsExpireDate.after(new Date());
	}

	@Override
	public boolean isEnabled() {
		return this.enabled;
	}

	public void setEnabled(boolean enabled) {
		this.enabled = enabled;
	}

	@Override
	public String toString() {
		ToStringBuilder sb = new ToStringBuilder(this,
				ToStringStyle.SHORT_PREFIX_STYLE).append("id", this.id).append(
				"username", this.username);

		return sb.toString();
	}

	@Override
	public boolean equals(Object other) {
		if (!(other instanceof User)) {
			return false;
		}
		User castOther = (User) other;
		return new EqualsBuilder().append(this.getUsername(),
				castOther.getUsername()).isEquals();
	}

	@Override
	public int hashCode() {
		return new HashCodeBuilder().append(getUsername()).toHashCode();
	}

}
